#include "onb.h"

namespace venus {
	#define ONB_EPSILON 0.01f

		void ONB::InitFromU( const Vector3& a_U ) {
			const Vector3 n( 1.0f, 0.f, 0.f ); 
			const Vector3 m( 0.f, 1.f, 0.f );
			_U = Normalize(a_U);
			
			_V = Cross( _U, n );
			if ( _V.Length() < ONB_EPSILON )
				_V = Cross( _U, m );

			_W = Cross( _U, _V );
		}

		void ONB::InitFromV( const Vector3& a_V ) {
			const Vector3 n( 1.0f, 0.f, 0.f ); 
			const Vector3 m( 0.f, 1.f, 0.f );

			_V = Normalize(a_V);

			_U = Cross( _V, n );
			if ( _U.Length() < ONB_EPSILON )
				_U = Cross( _V, m );

			_W = Cross( _U, _V );
		}

		void ONB::InitFromW( const Vector3& a_W ) {
			const Vector3 n( 1.0f, 0.f, 0.f ); 
			const Vector3 m( 0.f, 1.f, 0.f );

			_W = Normalize(a_W);

			_U = Cross( _W, n );
			if ( _U.Length() < ONB_EPSILON )
				_U = Cross( _W, m );

			_V = Cross( _W, _U );
		}

		void ONB::InitFromUV( const Vector3& a_U, const Vector3& a_V ) {
			_U = Normalize(a_U);
			_W = Normalize(Cross( a_U, a_V ));
			_V = Cross( _W, _U );
		}

		void ONB::InitFromVU( const Vector3& a_V, const Vector3& a_U ) {
			_V = Normalize(a_V);
			_W = Normalize(Cross( a_U, a_V ));
			_U = Cross( _V, _W );
		}

		void ONB::InitFromUW( const Vector3& a_U, const Vector3& a_W ) {
			_U = Normalize(a_U);
			_V = Normalize(Cross( a_W, a_U ));
			_W = Cross( _U, _V );
		}

		void ONB::InitFromWU( const Vector3& a_W, const Vector3& a_U ) {
			_W = Normalize(a_W);
			_V = Normalize(Cross( a_W, a_U ));
			_U = Cross( _V, _W );
		}

		void ONB::InitFromVW( const Vector3& a_V, const Vector3& a_W ) {
			_V = Normalize(a_V);
			_U = Normalize(Cross( a_V, a_W ));
			_W = Cross( _U, _V );
		}

		void ONB::InitFromWV( const Vector3& a_W, const Vector3& a_V ) {
			_W = Normalize(a_W);
			_U = Normalize(Cross( a_V, a_W ));
			_V = Cross( _W, _U );
		}

		istream& operator>>( istream& a_IStream, ONB& a_ONB ) {
			Vector3 u, v, w;
			a_IStream >> u >> v >> w;
			a_ONB.InitFromUV( u, v );
			return a_IStream;
		}


		ostream& operator<<( ostream& a_OStream, const ONB& a_ONB ) {
			a_OStream << a_ONB.U() << "\n" << a_ONB.V() << "\n" << a_ONB.W() << "\n";
			return a_OStream;
		}


		//bool operator==( const ONB& a_ONB1, const ONB& a_ONB2 )
		//{
		//	/************************************************************************
		//	 * !!!!!!!!!!!!!!!!!is this comparison reliable for float or double types?
		//	 ************************************************************************/
		//	return a_ONB1.U() == a_ONB2.U() &&
		//		a_ONB1.V() == a_ONB2.V() &&
		//		a_ONB1.W() == a_ONB2.W();
		//}
}

